// parsing:

int skip_whitespace () {
   int c;
   do {
      c = _getchar();
   } while (c == ' ' || c == '\n');
   lastchar = c;
   return c;
}

Atom* parse_list () {
   List *list = NULL, *next = NULL;
   while (1) {
      if (lastchar == -1 || lastchar == ' ' || lastchar == '\n')
         skip_whitespace();
      if (lastchar == ')') {
         lastchar = -1;
         break;
      }
      Atom *at = parse();
      List *tail = cons(at, NULL);
      if (next) {
         next->tail = tail;
      } else {
         list = next = tail;
      }
      next = tail;
   }
   return create_list(list);
}

Atom* parse_symbol (int c) {
   int buf[65536], n = 1, stop_at;
   if (lastchar != -1) {
      buf[n] = lastchar;
      lastchar = -1;
      n++;
   }
   switch (c) {
   case '"':
   case '\'':
      stop_at = c;
      do {
         if (c == '\\') {
            c = _getchar();
            switch (c) {
               case 'b': c = '\b'; break;
               case 'n': c = '\n'; break;
               case 't': c = '\t';
            }
         }
         buf[n] = c;
         c = _getchar();
         n ++;
      } while (c != stop_at && n < 65536);
      lastchar = -1;
   default:
      while (n < 65536 && c != ' ' && c != '\n' && c != '(' && c != ')') {
         buf[n] = c;
         c = _getchar();
         n ++;
      }
      lastchar = c;
   }
   if (n == 1)
      return NULL;
   buf[0] = n-1;
   if (symbols_are_equal(buf, nil_symb))
      return NULL;
   return create_symbol(duplicate_symbol(buf));
}

// TODO this routine needs rework, very bad quality code

Atom* parse_int (int c) {
   char neg = 0;
   int value = 0;
   int input_processed = 0;
   int firstchar = c;
   if (c == '+') {
   } else if (c == '-') {
      neg = 1;
   } else if (c >= '0' && c <= '9') {
      value += (c - '0');
      input_processed = 1;
      lastchar = -1;
   }
   while (1) {
      c = _getchar();
      if (c >= '0' && c <= '9') {
         if (!input_processed)
            input_processed = 1;
         value *= 10;
         value += (c - '0');
      } else {
         lastchar = c;
         break;
      }
      if (value < 0)
         return NULL;
   }
   if (!input_processed) {
      input_processed = firstchar;
      firstchar = lastchar;
      lastchar = input_processed;
      return parse_symbol(firstchar);
   }
   if (neg)
      value = -value;
   return create_int(value);
}

Atom* parse () {
   if (lastchar == -1 || lastchar == ' ' || lastchar == '\n')
      skip_whitespace();
   int c = lastchar;
   lastchar = -1;
   if (c == '(') {
      return parse_list();
   } else if (c == '-' || c == '+' || (c >= '0' && c <= '9')) {
      return parse_int(c);
   } else if (c == ';') {
      while (c != '\n')
         c = _getchar();
      return parse();
   } else if (c == ')') {
      return _warning("PARSE" EXTRA_PARENTHESIS);
   } else {
      return parse_symbol(c);
   }
}
